"""
项目：Ai-Engineer自适应工程设计自动化插件
作者：刘昊轩、李佳音、刘伟伟、杨明久（排序不分先后）
©版权保护
"""
# src/manager/autocad_manager.py
import json
import logging
from typing import Optional, Dict, Any
import pythoncom
from pyautocad import Autocad, APoint


class AutoCADManager:
    def __init__(self):
        self._init_com()
        self.acad = self._connect_autocad()

    def _init_com(self):
        """初始化COM线程"""
        pythoncom.CoInitialize()

    def _connect_autocad(self):
        """自动检测版本的连接方法"""
        try:
            # 尝试新版本连接方式
            return Autocad(create_if_not_exists=True)
        except ImportError as ie:
            logging.error("无法导入 pyautocad 模块: %s", str(ie))
            raise ImportError("请确认已安装 pyautocad 库") from ie
        except RuntimeError as re:
            logging.error("运行时错误: %s", str(re))
            return self._connect_via_com()
        except Exception as e:
            logging.error("未知错误: %s", str(e))
            raise RuntimeError("无法连接 AutoCAD，请检查环境配置") from e

    def _connect_via_com(self):
        """直接使用win32com连接"""
        try:
            import win32com.client
            return win32com.client.Dispatch("AutoCAD.Application.25")  # 25对应2025版本
        except Exception as e:
            raise RuntimeError(
                "无法连接AutoCAD，请确认：\n"
                "1. AutoCAD 2025已安装\n"
                "2. 以管理员权限运行程序\n"
                f"技术细节：{str(e)}"
            )

    def _init_layers(self):
        """安全初始化图层"""
        try:
            layers = ["轮廓线", "尺寸线", "中心线"]
            doc = self.acad.ActiveDocument
            for name in layers:
                if not any(layer.Name == name for layer in doc.Layers):
                    new_layer = doc.Layers.Add(name)
                    print(f"已创建图层：{new_layer.Name}")
        except Exception as e:
            print(f"图层初始化警告：{str(e)}")

    class EntityProcessor:
        def __init__(self):
            self.entities = []  # 确保初始化

        def load_entities(self, source):
            """加载实体并验证"""
            try:
                self.entities = self._fetch_entities(source)
            except Exception as e:
                logging.error("实体加载失败: %s", str(e))
                self.entities = []  # 失败时重置为空列表

        def _fetch_entities(self, source):
            if isinstance(source, dict):
                entities = source.get('entities')
                if entities is None:
                    logging.warning("源数据中 'entities' 字段不存在，使用空列表")
                    return []
                elif not isinstance(entities, list):
                    logging.warning("源数据中 'entities' 字段不是有效的列表，尝试转换")
                    try:
                        # 这里可以根据实际情况进行更复杂的转换逻辑
                        entities = [entities]  # 简单地将其转换为包含单个元素的列表
                    except Exception:
                        logging.error("无法将 'entities' 字段转换为列表，使用空列表")
                        return []
                return entities
            else:
                logging.error("源数据不是有效的字典，使用空列表")
                return []

        def process(self):
            """安全的实体处理"""
            if not self.entities:
                logging.warning("无实体需要处理")
                return

            for idx, entity in enumerate(self.entities):
                try:
                    self._process_entity(entity)
                except Exception as e:
                    logging.error("处理实体失败 [索引:%d]: %s", idx, str(e))

        def _process_entity(self, entity):
            # 这里是处理单个实体的逻辑
            logging.info("处理实体: %s", entity)

    def execute_command(self, command):
        """执行绘图命令"""
        if not isinstance(command.get("entities"), list):
            logging.error("Invalid command format: missing 'entities' list")
            return []

        results = []
        for idx, entity in enumerate(command["entities"]):
            try:
                if not isinstance(entity, dict):
                    raise ValueError(f"Entity {idx} is not a dictionary")

                entity_type = entity.get("type")
                if not entity_type:
                    raise ValueError(f"Entity {idx} missing 'type' field")

                if entity_type == "circle":
                    results.append(self._draw_circle(entity))
                elif entity_type == "rectangle":
                    results.append(self._draw_rectangle(entity))
                elif entity_type == "gear":
                    results.append(self._draw_gear(entity))
                elif entity_type == "bolt":
                    results.append(self._draw_bolt(entity))
                else:
                    logging.warning("跳过未知实体类型: %s", entity_type)
            except Exception as e:
                logging.error("处理实体失败 [索引:%d]: %s", idx, str(e))

        return results

    def _draw_circle(self, params):
        # 修改为使用 self.acad
        return self.acad.model.AddCircle(
            center=APoint(*params["center"]),
            radius=params["radius"]
        )

    def _draw_rectangle(self, params):
        start = APoint(*params["start"])
        end = APoint(start.x + params["width"], start.y + params["height"])
        # 修改为使用 self.acad
        lines = [
            self.acad.model.AddLine(start, APoint(end.x, start.y)),  # 上边
            self.acad.model.AddLine(APoint(end.x, start.y), end),  # 右边
            self.acad.model.AddLine(end, APoint(start.x, end.y)),  # 下边
            self.acad.model.AddLine(APoint(start.x, end.y), start)  # 左边
        ]
        return lines

    def _draw_gear(self, params):
        # 这里只是简单示例，实际绘制齿轮需要更复杂的逻辑
        diameter = params["diameter"]
        print(f"绘制直径为 {diameter} 的齿轮")
        # 可以在这里添加具体的齿轮绘制代码
        return None

    def _draw_bolt(self, params):
        # 这里只是简单示例，实际绘制螺栓需要更复杂的逻辑
        size = params["size"]
        print(f"绘制尺寸为 {size} 的螺栓")
        # 可以在这里添加具体的螺栓绘制代码
        return None


class CADExecutionError(Exception):
    """CAD 命令执行异常"""

    def __init__(
            self,
            command: str,
            error_code: str,
            error_message: str,
            technical_details: Optional[Dict[str, Any]] = None,
            suggested_fix: Optional[str] = None
    ):
        super().__init__()
        """
        初始化 CAD 执行错误

        参数：
        - command: 导致错误的 CAD 命令
        - error_code: 错误代码（如 "E_INVALID_POINT"）
        - error_message: 用户友好的错误信息
        - technical_details: 技术细节（可选）
        - suggested_fix: 建议的修复方法（可选）
        """
        self.command = command
        self.error_code = error_code
        self.error_message = error_message
        self.technical_details = technical_details or {}
        self.suggested_fix = suggested_fix

        # 构造完整的错误信息
        full_message = f"CAD 命令执行失败：{error_message}\n命令：{command}"
        if suggested_fix:
            full_message += f"\n建议修复：{suggested_fix}"
        super().__init__(full_message)

    @property
    def user_message(self) -> str:
        """返回用户友好的错误信息"""
        return self.error_message

    @property
    def debug_info(self) -> Dict[str, Any]:
        """返回调试信息"""
        return {
            "command": self.command,
            "error_code": self.error_code,
            "technical_details": self.technical_details,
            "suggested_fix": self.suggested_fix
        }

    @classmethod
    def from_autocad_error(cls, command: str, autocad_error: Exception) -> "CADExecutionError":
        """从 AutoCAD 原生异常构造 CADExecutionError"""
        error_code = getattr(autocad_error, "error_code", "UNKNOWN")
        error_message = cls._map_error_code_to_message(error_code)

        return cls(
            command=command,
            error_code=error_code,
            error_message=error_message,
            technical_details={
                "autocad_error": str(autocad_error),
                "error_type": type(autocad_error).__name__
            }
        )

    @staticmethod
    def _map_error_code_to_message(error_code: str) -> str:
        """将错误代码映射为用户友好的信息"""
        error_messages = {
            "E_INVALID_POINT": "无效的坐标点",
            "E_LAYER_NOT_FOUND": "图层不存在",
            "E_ENTITY_NOT_FOUND": "实体未找到",
            "E_OUT_OF_RANGE": "参数超出允许范围",
            "E_INVALID_INPUT": "输入参数无效",
            "UNKNOWN": "未知错误"
        }
        return error_messages.get(error_code, error_messages["UNKNOWN"])

    def log_error(self, logger):
        """记录错误日志"""
        logger.error(
            "CAD 命令执行失败：%s\n命令：%s\n技术细节：%s",
            self.error_message,
            self.command,
            json.dumps(self.technical_details, indent=2)
        )